CurrentThreadTransactionalConnectionProvider.java
package org.codefilarete.stalactite.engine;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.Set;
import org.codefilarete.stalactite.sql.CommitListener;
import org.codefilarete.stalactite.sql.ConnectionConfiguration;
import org.codefilarete.stalactite.sql.CurrentThreadConnectionProvider;
import org.codefilarete.stalactite.sql.RollbackListener;
import org.codefilarete.stalactite.sql.TransactionAwareConnexionWrapper;
import org.codefilarete.tool.collection.KeepOrderSet;
import org.codefilarete.tool.exception.Exceptions;
/**
* {@link org.codefilarete.stalactite.sql.ConnectionProvider} made to match expected contract of {@link PersistenceContext} connection configuration.
* This implementation uses {@link ThreadLocal} to store and provide connections.
*
* @author Guillaume Mary
*/
public class CurrentThreadTransactionalConnectionProvider implements ConnectionConfiguration.TransactionalConnectionProvider {
private final CurrentThreadConnectionProvider jdbcConnectionProvider;
private final Set<CommitListener> commitListeners = new KeepOrderSet<>();
private final Set<RollbackListener> rollbackListeners = new KeepOrderSet<>();
public CurrentThreadTransactionalConnectionProvider(DataSource dataSource) {
this.jdbcConnectionProvider = new CurrentThreadConnectionProvider(dataSource);
}
@Override
public Connection giveConnection() {
return new TransactionAwareConnexionWrapper(this.jdbcConnectionProvider.giveConnection(), commitListeners, rollbackListeners);
}
/**
* Implementation based on a {@link Savepoint} on current {@link Connection} to execute given operation.
*
* @param jdbcOperation a sql operation that will call {@link #giveConnection()} to execute its statements.
*/
@Override
@SuppressWarnings("resource" /* put for non-closed Connection which is normal here */)
public void executeInNewTransaction(JdbcOperation jdbcOperation) {
Connection currentConnection = giveConnection();
Savepoint savepoint = null;
try {
savepoint = currentConnection.setSavepoint();
jdbcOperation.execute(currentConnection);
} catch (Exception e) {
if (savepoint != null) {
try {
currentConnection.rollback(savepoint);
throw Exceptions.asRuntimeException(e);
} catch (SQLException e1) {
throw Exceptions.asRuntimeException(e1);
}
} else {
// else savepoint can't be created, let's throw an exception
throw Exceptions.asRuntimeException(e);
}
}
try {
currentConnection.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public void addCommitListener(CommitListener commitListener) {
this.commitListeners.add(commitListener);
}
@Override
public void addRollbackListener(RollbackListener rollbackListener) {
this.rollbackListeners.add(rollbackListener);
}
}